home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 25 / AACD 25.iso / AACD / Magazine / Online / QMail / source / dns.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-04-15  |  8.2 KB  |  403 lines

  1. #include <stdio.h>
  2. #include <netdb.h>
  3. #include <sys/types.h>
  4. #include <netinet/in.h>
  5. #include <arpa/nameser.h>
  6. #include <resolv.h>
  7. #include <errno.h>
  8. extern int res_query();
  9. extern int res_search();
  10. extern int errno;
  11. extern int h_errno;
  12. #include "ip.h"
  13. #include "ipalloc.h"
  14. #include "fmt.h"
  15. #include "alloc.h"
  16. #include "str.h"
  17. #include "stralloc.h"
  18. #include "dns.h"
  19. #include "case.h"
  20.  
  21. static unsigned short getshort(c) unsigned char *c;
  22. { unsigned short u; u = c[0]; return (u << 8) + c[1]; }
  23.  
  24. static union { HEADER hdr; unsigned char buf[PACKETSZ]; } response;
  25. static int responselen;
  26. static unsigned char *responseend;
  27. static unsigned char *responsepos;
  28.  
  29. static int numanswers;
  30. static char name[MAXDNAME];
  31. static struct ip_address ip;
  32. unsigned short pref;
  33.  
  34. static stralloc glue = {0};
  35.  
  36. static int (*lookup)() = res_query;
  37.  
  38. static int resolve(domain,type)
  39. stralloc *domain;
  40. int type;
  41. {
  42.  int n;
  43.  int i;
  44.  
  45.  errno = 0;
  46.  if (!stralloc_copy(&glue,domain)) return DNS_MEM;
  47.  if (!stralloc_0(&glue)) return DNS_MEM;
  48.  responselen = lookup(glue.s,C_IN,type,response.buf,sizeof(response));
  49.  if (responselen <= 0)
  50.   {
  51.    if (errno == ECONNREFUSED) return DNS_SOFT;
  52.    if (h_errno == TRY_AGAIN) return DNS_SOFT;
  53.    return DNS_HARD;
  54.   }
  55.  if (responselen >= sizeof(response))
  56.    responselen = sizeof(response);
  57.  responseend = response.buf + responselen;
  58.  responsepos = response.buf + sizeof(HEADER);
  59.  n = ntohs(response.hdr.qdcount);
  60.  while (n-- > 0)
  61.   {
  62.    i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME);
  63.    if (i < 0) return DNS_SOFT;
  64.    responsepos += i;
  65.    i = responseend - responsepos;
  66.    if (i < QFIXEDSZ) return DNS_SOFT;
  67.    responsepos += QFIXEDSZ;
  68.   }
  69.  numanswers = ntohs(response.hdr.ancount);
  70.  return 0;
  71. }
  72.  
  73. static int findname(wanttype)
  74. int wanttype;
  75. {
  76.  unsigned short rrtype;
  77.  unsigned short rrdlen;
  78.  int i;
  79.  
  80.  if (numanswers <= 0) return 2;
  81.  --numanswers;
  82.  if (responsepos == responseend) return DNS_SOFT;
  83.  
  84.  i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME);
  85.  if (i < 0) return DNS_SOFT;
  86.  responsepos += i;
  87.  
  88.  i = responseend - responsepos;
  89.  if (i < 4 + 3 * 2) return DNS_SOFT;
  90.    
  91.  rrtype = getshort(responsepos);
  92.  rrdlen = getshort(responsepos + 8);
  93.  responsepos += 10;
  94.  
  95.  if (rrtype == wanttype)
  96.   {
  97.    if (dn_expand(response.buf,responseend,responsepos,name,MAXDNAME) < 0)
  98.      return DNS_SOFT;
  99.    responsepos += rrdlen;
  100.    return 1;
  101.   }
  102.    
  103.  responsepos += rrdlen;
  104.  return 0;
  105. }
  106.  
  107. static int findip(wanttype)
  108. int wanttype;
  109. {
  110.  unsigned short rrtype;
  111.  unsigned short rrdlen;
  112.  int i;
  113.  
  114.  if (numanswers <= 0) return 2;
  115.  --numanswers;
  116.  if (responsepos == responseend) return DNS_SOFT;
  117.  
  118.  i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME);
  119.  if (i < 0) return DNS_SOFT;
  120.  responsepos += i;
  121.  
  122.  i = responseend - responsepos;
  123.  if (i < 4 + 3 * 2) return DNS_SOFT;
  124.    
  125.  rrtype = getshort(responsepos);
  126.  rrdlen = getshort(responsepos + 8);
  127.  responsepos += 10;
  128.  
  129.  if (rrtype == wanttype)
  130.   {
  131.    if (rrdlen < 4)
  132.      return DNS_SOFT;
  133.    ip.d[0] = responsepos[0];
  134.    ip.d[1] = responsepos[1];
  135.    ip.d[2] = responsepos[2];
  136.    ip.d[3] = responsepos[3];
  137.    responsepos += rrdlen;
  138.    return 1;
  139.   }
  140.    
  141.  responsepos += rrdlen;
  142.  return 0;
  143. }
  144.  
  145. static int findmx(wanttype)
  146. int wanttype;
  147. {
  148.  unsigned short rrtype;
  149.  unsigned short rrdlen;
  150.  int i;
  151.  
  152.  if (numanswers <= 0) return 2;
  153.  --numanswers;
  154.  if (responsepos == responseend) return DNS_SOFT;
  155.  
  156.  i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME);
  157.  if (i < 0) return DNS_SOFT;
  158.  responsepos += i;
  159.  
  160.  i = responseend - responsepos;
  161.  if (i < 4 + 3 * 2) return DNS_SOFT;
  162.    
  163.  rrtype = getshort(responsepos);
  164.  rrdlen = getshort(responsepos + 8);
  165.  responsepos += 10;
  166.  
  167.  if (rrtype == wanttype)
  168.   {
  169.    if (rrdlen < 3)
  170.      return DNS_SOFT;
  171.    pref = (responsepos[0] << 8) + responsepos[1];
  172.    if (dn_expand(response.buf,responseend,responsepos + 2,name,MAXDNAME) < 0)
  173.      return DNS_SOFT;
  174.    responsepos += rrdlen;
  175.    return 1;
  176.   }
  177.    
  178.  responsepos += rrdlen;
  179.  return 0;
  180. }
  181.  
  182. void dns_init(flagsearch)
  183. int flagsearch;
  184. {
  185.  res_init();
  186.  if (flagsearch) lookup = res_search;
  187. }
  188.  
  189. int dns_cname(sa)
  190. stralloc *sa;
  191. {
  192.  int r;
  193.  int loop;
  194.  for (loop = 0;loop < 10;++loop)
  195.   {
  196.    if (!sa->len) return loop;
  197.    if (sa->s[sa->len - 1] == ']') return loop;
  198.    if (sa->s[sa->len - 1] == '.') { --sa->len; continue; }
  199.    switch(resolve(sa,T_ANY))
  200.     {
  201.      case DNS_MEM: return DNS_MEM;
  202.      case DNS_SOFT: return DNS_SOFT;
  203.      case DNS_HARD: return loop;
  204.      default:
  205.        while ((r = findname(T_CNAME)) != 2)
  206.     {
  207.      if (r == DNS_SOFT) return DNS_SOFT;
  208.      if (r == 1)
  209.       {
  210.        if (!stralloc_copys(sa,name)) return DNS_MEM;
  211.        break;
  212.       }
  213.     }
  214.        if (r == 2) return loop;
  215.     }
  216.   }
  217.  return DNS_HARD; /* alias loop */
  218. }
  219.  
  220. #define FMT_IAA 40
  221.  
  222. static int iaafmt(s,ip)
  223. char *s;
  224. struct ip_address *ip;
  225. {
  226.  unsigned int i;
  227.  unsigned int len;
  228.  len = 0;
  229.  i = fmt_ulong(s,(unsigned long) ip->d[3]); len += i; if (s) s += i;
  230.  i = fmt_str(s,"."); len += i; if (s) s += i;
  231.  i = fmt_ulong(s,(unsigned long) ip->d[2]); len += i; if (s) s += i;
  232.  i = fmt_str(s,"."); len += i; if (s) s += i;
  233.  i = fmt_ulong(s,(unsigned long) ip->d[1]); len += i; if (s) s += i;
  234.  i = fmt_str(s,"."); len += i; if (s) s += i;
  235.  i = fmt_ulong(s,(unsigned long) ip->d[0]); len += i; if (s) s += i;
  236.  i = fmt_str(s,".in-addr.arpa."); len += i; if (s) s += i;
  237.  return len;
  238. }
  239.  
  240. int dns_ptr(sa,ip)
  241. stralloc *sa;
  242. struct ip_address *ip;
  243. {
  244.  int r;
  245.  
  246.  if (!stralloc_ready(sa,iaafmt((char *) 0,ip))) return DNS_MEM;
  247.  sa->len = iaafmt(sa->s,ip);
  248.  switch(resolve(sa,T_PTR))
  249.   {
  250.    case DNS_MEM: return DNS_MEM;
  251.    case DNS_SOFT: return DNS_SOFT;
  252.    case DNS_HARD: return DNS_HARD;
  253.   }
  254.  while ((r = findname(T_PTR)) != 2)
  255.   {
  256.    if (r == DNS_SOFT) return DNS_SOFT;
  257.    if (r == 1)
  258.     {
  259.      if (!stralloc_copys(sa,name)) return DNS_MEM;
  260.      return 0;
  261.     }
  262.   }
  263.  return DNS_HARD;
  264. }
  265.  
  266. static int dns_ipplus(ia,sa,pref)
  267. ipalloc *ia;
  268. stralloc *sa;
  269. int pref;
  270. {
  271.  int r;
  272.  struct ip_mx ix;
  273.  
  274.  if (sa->len && (sa->s[0] == '['))
  275.   {
  276.    if (!stralloc_copy(&glue,sa)) return DNS_MEM;
  277.    if (!stralloc_0(&glue)) return DNS_MEM;
  278.    ix.pref = 0;
  279.    if (!glue.s[ip_scanbracket(glue.s,&ix.ip)])
  280.     {
  281.      if (!ipalloc_append(ia,&ix)) return DNS_MEM;
  282.      return 0;
  283.     }
  284.   }
  285.  
  286.  switch(resolve(sa,T_A))
  287.   {
  288.    case DNS_MEM: return DNS_MEM;
  289.    case DNS_SOFT: return DNS_SOFT;
  290.    case DNS_HARD: return DNS_HARD;
  291.   }
  292.  while ((r = findip(T_A)) != 2)
  293.   {
  294.    ix.ip = ip;
  295.    ix.pref = pref;
  296.    if (r == DNS_SOFT) return DNS_SOFT;
  297.    if (r == 1)
  298.      if (!ipalloc_append(ia,&ix)) return DNS_MEM;
  299.   }
  300.  return 0;
  301. }
  302.  
  303. int dns_ip(ia,sa)
  304. ipalloc *ia;
  305. stralloc *sa;
  306. {
  307.  if (!ipalloc_readyplus(ia,0)) return DNS_MEM;
  308.  ia->len = 0;
  309.  return dns_ipplus(ia,sa,0);
  310. }
  311.  
  312. int dns_mxip(ia,sa,random)
  313. ipalloc *ia;
  314. stralloc *sa;
  315. unsigned long random;
  316. {
  317.  int r;
  318.  struct mx { stralloc sa; unsigned short p; } *mx;
  319.  int nummx;
  320.  int i;
  321.  int j;
  322.  int flagsoft;
  323.  
  324.  if (!ipalloc_readyplus(ia,0)) return DNS_MEM;
  325.  ia->len = 0;
  326.  
  327.  if (sa->len && (sa->s[0] == '['))
  328.   {
  329.    struct ip_mx ix;
  330.    if (!stralloc_copy(&glue,sa)) return DNS_MEM;
  331.    if (!stralloc_0(&glue)) return DNS_MEM;
  332.    ix.pref = 0;
  333.    if (!glue.s[ip_scanbracket(glue.s,&ix.ip)])
  334.     {
  335.      if (!ipalloc_append(ia,&ix)) return DNS_MEM;
  336.      return 0;
  337.     }
  338.   }
  339.  
  340.  switch(resolve(sa,T_MX))
  341.   {
  342.    case DNS_MEM: return DNS_MEM;
  343.    case DNS_SOFT: return DNS_SOFT;
  344.    case DNS_HARD: return dns_ip(ia,sa);
  345.   }
  346.  
  347.  mx = (struct mx *) alloc(numanswers * sizeof(struct mx));
  348.  if (!mx) return DNS_MEM;
  349.  nummx = 0;
  350.  
  351.  while ((r = findmx(T_MX)) != 2)
  352.   {
  353.    if (r == DNS_SOFT) { alloc_free(mx); return DNS_SOFT; }
  354.    if (r == 1)
  355.     {
  356.      mx[nummx].p = pref;
  357.      mx[nummx].sa.s = 0;
  358.      if (!stralloc_copys(&mx[nummx].sa,name))
  359.       {
  360.        while (nummx > 0) alloc_free(mx[--nummx].sa.s);
  361.        alloc_free(mx); return DNS_MEM;
  362.       }
  363.      ++nummx;
  364.     }
  365.   }
  366.  
  367.  if (!nummx) return dns_ip(ia,sa); /* e.g., CNAME -> A */
  368.  
  369.  flagsoft = 0;
  370.  while (nummx > 0)
  371.   {
  372.    unsigned long numsame;
  373.  
  374.    i = 0;
  375.    numsame = 1;
  376.    for (j = 1;j < nummx;++j)
  377.      if (mx[j].p < mx[i].p)
  378.       {
  379.        i = j;
  380.        numsame = 1;
  381.       }
  382.      else if (mx[j].p == mx[i].p)
  383.       {
  384.        ++numsame;
  385.        random = random * 69069 + 1;
  386.        if ((random / 2) < (2147483647 / numsame))
  387.          i = j;
  388.       }
  389.  
  390.    switch(dns_ipplus(ia,&mx[i].sa,mx[i].p))
  391.     {
  392.      case DNS_MEM: case DNS_SOFT:
  393.        flagsoft = 1; break;
  394.     }
  395.  
  396.    alloc_free(mx[i].sa.s);
  397.    mx[i] = mx[--nummx];
  398.   }
  399.  
  400.  alloc_free(mx);
  401.  return flagsoft;
  402. }
  403.